package org.flexharmony.eclipse;

import static org.flexharmony.eclipse.utils.CommonMethods.*;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.flexharmony.eclipse.domain.IncludedSourceFolder;
import org.flexharmony.eclipse.properties.ConfigurationBuilder;
import org.flexharmony.eclipse.properties.PropertiesConstants;
import org.flexharmony.eclipse.properties.classinclusion.IncludedSourceFolderMarshaller;
import org.flexharmony.harmonizer.Harmonizer;
import org.flexharmony.harmonizer.config.HarmonyConfiguration;

public class HarmonyProjectBuilder extends IncrementalProjectBuilder
{
  static public final String BUILDER_ID = HarmonyPlugin.PLUGIN_ID + ".harmonyBuilder";
  
  public HarmonyProjectBuilder()
  {}

  @SuppressWarnings("unchecked")
  @Override
  protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException
  {
    IProject project = getProject();

    List<IncludedSourceFolder> includedFolders = IncludedSourceFolderMarshaller.unmarshall(project);
    if (includedFolders.size() == 0) return null;

    String flexSrcDirName = project.getPersistentProperty(PropertiesConstants.FLEX_SRC_DIR_NAME_QNAME);
    if ((flexSrcDirName == null) || (flexSrcDirName.length() == 0)) return null;
    IFolder flexSrcDir = project.getFolder(flexSrcDirName);
    
    IJavaProject javaProject = JavaCore.create(project);
    IPath binDirPath = javaProject.readOutputLocation();
    IFolder binDir = project.getFolder(binDirPath.removeFirstSegments(1));

    
    List<IFile> classFiles = null;
    if ((kind == INCREMENTAL_BUILD) || (kind == AUTO_BUILD))
    {
      IResourceDelta delta = getDelta(getProject());
      if (delta != null)
      {
        classFiles = getDeltaClassFiles(delta, binDirPath);
      }
    }
    else if ((kind == FULL_BUILD) || (kind == CLEAN_BUILD))
    {
      classFiles = getAllClassFiles(binDir, binDir.getFullPath());
    }
    
    List<IFile> filteredClassFiles = new ArrayList<IFile>();
    for (IFile classFile : classFiles)
    {
      IPath classRelativePath = classFile.getFullPath().removeFirstSegments(binDirPath.segmentCount());
      String javaFilePathName = classRelativePath.toString();
      javaFilePathName = javaFilePathName.substring(0, (javaFilePathName.length() - 6)) + ".java";
      
      IPath sourceFolderPath = findJavaSourceRoot(project, new Path(javaFilePathName));
      if (sourceFolderPath != null) 
      {
        IPath javaFilePath = sourceFolderPath.append(javaFilePathName);
        if (matchesPatterns(project, sourceFolderPath, javaFilePath, includedFolders))
        {
          filteredClassFiles.add(classFile);
        }
      }
    }

    if ((filteredClassFiles != null) && (filteredClassFiles.size() > 0))
    {
      ConfigurationBuilder configBuilder = new ConfigurationBuilder(getProject());
      HarmonyConfiguration harmonyConfig = configBuilder.createConfiguration();
      Harmonizer classHarmonizer = new Harmonizer(harmonyConfig);
      try
      {
        for (IFile classFile : filteredClassFiles)
        {
          File classOsFile = classFile.getLocation().toFile();
          monitor.setTaskName("Haromonizing " + classFile.getFullPath());
          classHarmonizer.harmonize(classOsFile);
          monitor.worked(1);
        }
        
        monitor.setTaskName("Writing action script updates.");
        classHarmonizer.writeUpdates();
        flexSrcDir.refreshLocal(IResource.DEPTH_INFINITE, monitor);
        monitor.worked(1);
      }
      catch (IOException ioexc)
      {
        throw new CoreException(new Status(IStatus.ERROR, HarmonyPlugin.PLUGIN_ID, ioexc.getMessage()));
      }
    }
    
    return null;
  }
  
  private List<IFile> getAllClassFiles(IFolder folder, IPath binDirPath) throws CoreException
  {
    List<IFile> classFiles = new ArrayList<IFile>();
    
    IResource[] children = folder.members();
    
    for (IResource child : children)
    {
      if (child instanceof IFile)
      {
        IFile file = (IFile)child;
        String fileName = file.getName();
        
        if (!fileName.endsWith(".class")) continue;
        
        IPath filePath = file.getFullPath();

        if (!binDirPath.isPrefixOf(filePath)) continue;
        
        classFiles.add(file);
      }
      else if (child instanceof IFolder)
      {
        classFiles.addAll(getAllClassFiles((IFolder)child, binDirPath));
      }
    }
    
    return classFiles;
  }

  
  private List<IFile> getDeltaClassFiles(IResourceDelta resourceDelta, IPath binDirPath)
  {
    IResource resource = resourceDelta.getResource();
    
    List<IFile> classFiles = new ArrayList<IFile>();
    if (resource instanceof IFile)
    {
      IFile classFile = (IFile)resource;
      if (binDirPath.isPrefixOf(resource.getFullPath()) && resource.getName().endsWith(".class"))
      {
        classFiles.add(classFile);
      }
    }
    else
    {
      IResourceDelta[] childDeltas = resourceDelta.getAffectedChildren();
      if (childDeltas != null)
      {
        for (IResourceDelta childDelta : childDeltas)
        {
          classFiles.addAll(getDeltaClassFiles(childDelta, binDirPath));
        }
      }
    }
    
    return classFiles;
  }
}
